import json

from typing import Union, List, Any, Dict
from django.core.handlers.wsgi import WSGIRequest
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render
from django.db.models.query import QuerySet

from product import models
import product.utils.work_with_stripe as work_with_stripe
import product.utils.order as order
import product.utils.utils as product_utils


class ProductUtils:
    """ Инструменты для обработки запроса связанного с продуктом """

    def get_template_for_displaying_single_product(
            self, request: WSGIRequest, pk: int) -> HttpResponse:
        """ Возвращаем шаблон для отображения отдельного продукта """

        product = models.Product.objects.get(pk=pk)
        price_in_another_currency = product_utils.ProductUtils().convert_ruble_to_another_currency(
            product.price,
            product.currency
        )
        price_in_another_currency = f'{product.currency} {price_in_another_currency}'
        context = {'product': product,
                   'price_in_another_currency': price_in_another_currency,
                   'show_buy_button': True}
        return render(request, 'product/single_product.html', context)


    def get_template_for_displaying_list_of_products(
            self, request: WSGIRequest) -> HttpResponse:
        """ Возвращаем шаблон для отображения списка продуктов """

        list_of_products = models.Product.objects.all()
        context = {'list_of_products': list_of_products}
        return render(request, 'product/list_of_products.html', context)


    def get_value_of_field_of_all_products(
            self,
            list_of_products: QuerySet,
            field_name: str,
            data_type) -> List[str]:
        """ Получаем значение поля всех продуктов """

        return [data_type(product[field_name]) for product in list_of_products]


    def get_price_in_other_currencies(
            self,
            price: int,
            string_format: bool = False) -> Dict[str, int]:
        """ Получаем цену в других валютах """

        result = {}
        currency_list = {
            'usd': 73,
            'eur': 79,
            'jpy': 11
        }

        for currency_rate in currency_list:
            final_price = int(price / currency_list[currency_rate])
            result[currency_rate] = str(final_price)

        if string_format:
            return json.dumps(currency_list)
        else:
            return result


    def convert_ruble_to_another_currency(self, price: int, currency: str) -> Any:
        """ Получаем цену в другой валюте """

        if currency == 'rub': return price
        currency_list = self.get_price_in_other_currencies(price)
        return currency_list[currency]


class BuyUtils:
    """ Инструменты для обработки запроса на покупку чего-то """

    def pay_with_payment_intent(self, pk: int) -> Any:
        """ Оплачиваем с помощью PaymentIntent """

        product = models.Product.objects.get(id=pk)
        custom_payment = work_with_stripe.CustomPaymentWithPaymentIntent(
            price=product.price,
            currency=product.currency
        )
        result = work_with_stripe.PaymentIntentApiStripe().pay_for_product_payment_intent(
            custom_payment
        )
        return JsonResponse(result)


    def perform_necessary_action(
            self,
            request: WSGIRequest,
            pk: int) -> JsonResponse:

        if 'session_to_pay_for_product' in request.GET:
            return self.pay_with_payment_intent(pk)
        else:
            message = f'Полученные параметры не обрабатываются: {request.GET}'
            raise ValueError(message)



class CartUtils:
    """ Инструменты для обработки запросов связанных с корзиной """

    def add_new_product_to_order(
            self,
            request: WSGIRequest) -> JsonResponse:
        """ Добавляем новый продукт в заказ """

        data = json.loads(request.body)
        product_id = data['product_id']
        last_order = order.OrderUtils().get_last_order()
        product = models.Product.objects.get(pk=product_id)
        response = order.OrderUtils().add_product_to_order(last_order, product)
        return JsonResponse(response)


    def display_order(self, request: WSGIRequest) -> HttpResponse:
        """ Отображаем заказ """

        order_products = order.OrderUtils().get_order_products()
        order_amount = order.OrderUtils().get_order_amount()
        order_quantity_of_products = order.OrderUtils().get_quantity_of_order_products()
        context = {
            'order_products': order_products,
            'order_amount': order_amount,
            'order_quantity_of_products': order_quantity_of_products,
        }
        return render(request, 'product/cart.html', context)


    def pay_custom_order(self) -> JsonResponse:
        """ Оплачиваем пользовательский заказ """

        order_products = order.OrderUtils().get_order_products(type_of_dict=False)
        custom_order = order.CustomOrderCheckoutSession(
            list_of_products=order_products
        )
        result = order.OrderUtils().pay_custom_order_checkout_session(
            custom_order
        )
        return JsonResponse(result)



    def perform_necessary_action(
            self,
            request: WSGIRequest) -> Union[HttpResponse, JsonResponse]:

        if 'add_product_to_cart' in request.GET:
            return self.add_new_product_to_order(request)
        elif 'pay_for_order' in request.GET:
            return self.pay_custom_order()
        else:
            message = f'Полученные параметры не обрабатываются: {request.GET}'
            raise ValueError(message)


    def get_necessary_information(
            self,
            request: WSGIRequest) -> Union[HttpResponse, JsonResponse]:
        """ Получаем необходимую информацию """

        if 'display_cart' in request.GET:
            return self.display_order(request)
        else:
            message = f'Полученные параметры не обрабатываются: {request.GET}'
            raise ValueError(message)
